package com.kapcb.assemble.filter;

import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;

/**
 * <a>Title: CFilterChain </a>
 * <a>Author: Kapcb <a>
 * <a>Description: CFilterChain <a>
 *
 * @author Kapcb
 * @version 1.0
 * @date 2024/4/18 21:19
 * @since 1.0
 */
public class CFilterChain<T extends FilterRequest, R extends FilterResponse> implements FilterChain<T, R> {

    /**
     * 过滤链数组
     */
    private Filter<T, R>[] filters;

    /**
     * 当前执行责任链的位置
     */
    private int position = 0;

    /**
     * 责任链中节点的数量
     */
    private int cnt = 0;

    /**
     * 目标方法
     */
    private BiConsumer<T, R> targetMethod;

    private CFilterChain() {
    }

    @Override
    public void doFilter(T request, R response) {
        if (this.cnt <= 0 || this.position >= this.cnt) {
            if (this.targetMethod != null) {
                targetMethod.accept(request, response);
            }
            return;
        }
        Filter<T, R> currentFilter = this.filters[this.position++];
        currentFilter.doFilter(request, response, this);
    }

    public static class FilterChainBuilder<T extends FilterRequest, R extends FilterResponse> {

        private int cnt = 0;

        private BiConsumer<T, R> targetMethod;

        private List<Filter<T, R>> filterList = Lists.newArrayList();

        private FilterChainBuilder() {
        }

        public static <T extends FilterRequest, R extends FilterResponse> FilterChainBuilder newBuilder() {
            return new FilterChainBuilder<T, R>();
        }

        public FilterChainBuilder<T, R> addFilter(Filter<T, R> filter) {
            if (Objects.isNull(filter)) {
                throw new IllegalArgumentException("chain can not be null, pls check your code!");
            }

            this.filterList.add(filter);
            this.cnt++;
            return this;
        }

        public FilterChainBuilder<T, R> addFilters(List<Filter<T, R>> filters) {
            if (CollectionUtils.isEmpty(filters)) {
                throw new IllegalArgumentException("chain can not be null, pls check your code!");
            }

            this.filterList.addAll(filters);
            this.cnt = this.filterList.size();
            return this;
        }

        public FilterChainBuilder<T, R> addTargetMethod(BiConsumer<T, R> targetMethod) {
            this.targetMethod = targetMethod;
            return this;
        }

        public FilterChain<T, R> build() {
            CFilterChain<T, R> filterChain = new CFilterChain<>();
            filterChain.cnt = this.cnt;
            filterChain.targetMethod = this.targetMethod;
            this.filterList.sort(Comparator.comparingInt(Filter::order));
            filterChain.filters = this.filterList.toArray(new Filter[this.filterList.size()]);
            return filterChain;
        }
    }
}
